---
title: Solana Playground
description:
  Learn how to build your first Solana program using the Anchor framework
  directly in your browser.
---

In this section, we'll build, deploy, and test a simple Solana program using the
Anchor framework. By the end, you'll have deployed your first program to the
Solana blockchain!

Solana Playground (Solpg) is a browser-based development environment that allows
you to quickly develop, deploy, and test Solana programs!

## Getting Started

Open a new tab in your web browser and navigate to https://beta.solpg.io/.

<Steps>

<Step>
### Create Playground Wallet

If you're new to Solana Playground, the first step is to create your Playground
Wallet. This wallet will allow you to interact with the Solana network right
from your browser.

#### Step 1. Connect to Playground

Click the "Not connected" button at the bottom left of the screen.

![Not Connected](/docs/quickstart/pg-not-connected.png)

#### Step 2. Create Your Wallet

You'll see an option to save your wallet's keypair. Optionally, save your
wallet's keypair for backup and then click "Continue".

![Create Playground Wallet](/docs/quickstart/pg-create-wallet.png)

You should now see your wallet's address, SOL balance, and connected cluster
(devnet by default) at the bottom of the window.

![Connected](/docs/quickstart/pg-connected.png)

<Callout>
  Your Playground Wallet will be saved in your browser's local storage. Clearing
  your browser cache will remove your saved wallet.
</Callout>

Some definitions you may find helpful:

- _wallet address_: a public key that serves as your unique identity on the
  Solana blockchain. Just like an email address is used to receive emails, your
  wallet address is used to receive SOL.
- _connection cluster_: a network of Solana nodes (computers running Solana
  validator client). Devnet is the cluster for developer testing.

</Step>
<Step>

### Get Devnet SOL

Before we start building, we first need some devnet SOL.

From a developer's perspective, SOL is required for two main use cases:

- To create accounts on the network where we store data or deploy programs
- To pay for transaction fees when we interact with the network

Below are two methods to fund your wallet with devnet SOL:

#### Option 1: Using the Playground Terminal

To fund your Playground wallet with devnet SOL. In the Playground terminal, run:

```shell filename="Terminal"
solana airdrop 5
```

#### Option 2: Using the Devnet Faucet

If the airdrop command doesn't work (due to rate limits or errors), you can use
the [Web Faucet](https://faucet.solana.com/).

- Enter your wallet address (found at the bottom of the Playground screen) and
  select an amount
- Click "Confirm Airdrop" to receive your devnet SOL

![Faucet Airdrop](/docs/quickstart/faucet-airdrop.gif)

</Step>

<Step>

### Create Anchor Project

First, open https://beta.solpg.io in a new browser tab.

- Click the "Create a new project" button on the left-side panel.

- Enter a project name, select Anchor as the framework, then click the "Create"
  button.

![New Project](/docs/quickstart/pg-new-project.gif)

You'll see a new project created with the program code in the `src/lib.rs` file.

```rust filename="lib.rs"
use anchor_lang::prelude::*;

// This is your program's public key and it will update
// automatically when you build the project.
declare_id!("11111111111111111111111111111111");

#[program]
mod hello_anchor {
    use super::*;
    pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {
        ctx.accounts.new_account.data = data;
        msg!("Changed data to: {}!", data); // Message will show up in the tx logs
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    // We must specify the space in order to initialize an account.
    // First 8 bytes are default account discriminator,
    // next 8 bytes come from NewAccount.data being type u64.
    // (u64 = 64 bits unsigned integer = 8 bytes)
    #[account(init, payer = signer, space = 8 + 8)]
    pub new_account: Account<'info, NewAccount>,
    #[account(mut)]
    pub signer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[account]
pub struct NewAccount {
    data: u64
}
```

<Accordions>
<Accordion title="Explanation">

For now, we'll only cover the high-level overview of the program code:

- The `declare_id!` macro specifies the on-chain address of your program. It
  will be automatically updated when we build the program in the next step.

  ```rust
  declare_id!("11111111111111111111111111111111");
  ```

- The `#[program]` attribute annotates a module containing functions that
  represent the program's instructions.

  ```rust
  #[program]
  mod hello_anchor {
      use super::*;
      pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {
          ctx.accounts.new_account.data = data;
          msg!("Changed data to: {}!", data); // Message will show up in the tx logs
          Ok(())
      }
  }
  ```

  In this example, the `initialize` instruction takes two parameters:

  1. `ctx: Context<Initialize>` - Provides access to the accounts required for
     this instruction, as specified in the `Initialize` struct.
  2. `data: u64` - An instruction parameter that will be passed in when the
     instruction is invoked.

  The function body sets the `data` field of `new_account` to the provided
  `data` argument and then prints a message to the program logs.

- The `#[derive(Accounts)]` macro is used to annotate a struct that specifies
  the accounts required for a particular instruction, where each field
  represents a separate account.

  The field types (ex. `Signer<'info>`) and constraints (ex. `#[account(mut)]`)
  are used by Anchor to automatically handle common security checks related to
  account validation.

  ```rust
  #[derive(Accounts)]
  pub struct Initialize<'info> {
      #[account(init, payer = signer, space = 8 + 8)]
      pub new_account: Account<'info, NewAccount>,
      #[account(mut)]
      pub signer: Signer<'info>,
      pub system_program: Program<'info, System>,
  }
  ```

- The `#[account]` attribute is used to annotate a struct that represents the
  data structure of an account created and owned by the program.

  ```rust
  #[account]
  pub struct NewAccount {
    data: u64
  }
  ```

</Accordion>
</Accordions>

</Step>
<Step>
### Build and Deploy Program

To build the program, simply run `build` in the terminal.

```shell filename="Terminal"
build
```

Notice that the address in `declare_id!()` has been updated. This is your
program's on-chain address.

<Accordions>
<Accordion title="Output">

```shell filename="Terminal"
$ build
Building...
Build successful. Completed in 1.46s.
```

</Accordion>
</Accordions>

Once the program is built, run `deploy` in the terminal to deploy the program to
the network (devnet by default). To deploy a program, SOL must be allocated to
the on-chain account that stores the program.

Before deployment, ensure you have enough SOL. You can get devnet SOL by either
running `solana airdrop 5` in the Playground terminal or using the
[Web Faucet](https://faucet.solana.com/).

```shell filename="Terminal"
deploy
```

<Accordions>
<Accordion title="Output">

```shell filename="Terminal"
$ deploy
Deploying... This could take a while depending on the program size and network conditions.
Warning: 1 transaction not confirmed, retrying...
Deployment successful. Completed in 19s.
```

</Accordion>
</Accordions>

Alternatively, you can also use the `Build` and `Deploy` buttons on the
left-side panel.

![Build and Deploy](/docs/quickstart/pg-build-deploy.png)

Once the program is deployed, you can now invoke its instructions.

</Step>
<Step>
### Test Program

Included with the starter code is a test file found in `tests/anchor.test.ts`.
This file demonstrates how to invoke the `initialize` instruction on the starter
program from the client.

```ts filename="anchor.test.ts"
// No imports needed: web3, anchor, pg and more are globally available

describe("Test", () => {
  it("initialize", async () => {
    // Generate keypair for the new account
    const newAccountKp = new web3.Keypair();

    // Send transaction
    const data = new BN(42);
    const txHash = await pg.program.methods
      .initialize(data)
      .accounts({
        newAccount: newAccountKp.publicKey,
        signer: pg.wallet.publicKey,
        systemProgram: web3.SystemProgram.programId,
      })
      .signers([newAccountKp])
      .rpc();
    console.log(`Use 'solana confirm -v ${txHash}' to see the logs`);

    // Confirm transaction
    await pg.connection.confirmTransaction(txHash);

    // Fetch the created account
    const newAccount = await pg.program.account.newAccount.fetch(
      newAccountKp.publicKey,
    );

    console.log("On-chain data is:", newAccount.data.toString());

    // Check whether the data on-chain is equal to local 'data'
    assert(data.eq(newAccount.data));
  });
});
```

To run the test file once the program is deployed, run `test` in the terminal.

```shell filename="Terminal"
test
```

You should see an output indicating that the test passed successfully.

<Accordions>
<Accordion title="Output">

```shell filename="Terminal"
$ test
Running tests...
  hello_anchor.test.ts:
  hello_anchor
    Use 'solana confirm -v 3TewJtiUz1EgtT88pLJHvKFzqrzDNuHVi8CfD2mWmHEBAaMfC5NAaHdmr19qQYfTiBace6XUmADvR4Qrhe8gH5uc' to see the logs
    On-chain data is: 42
    ✔ initialize (961ms)
  1 passing (963ms)
```

</Accordion>
</Accordions>

You can also use the `Test` button on the left-side panel.

![Run Test](/docs/quickstart/pg-test.png)

You can then view the transaction logs by running the `solana confirm -v`
command and specifying the transaction hash (signature) from the test output:

```shell filename="Terminal"
solana confirm -v [TxHash]
```

For example:

```shell filename="Terminal"
solana confirm -v 3TewJtiUz1EgtT88pLJHvKFzqrzDNuHVi8CfD2mWmHEBAaMfC5NAaHdmr19qQYfTiBace6XUmADvR4Qrhe8gH5uc
```

<Accordions>
<Accordion title="Output">

```shell filename="Terminal" {29-35}
$ solana confirm -v 3TewJtiUz1EgtT88pLJHvKFzqrzDNuHVi8CfD2mWmHEBAaMfC5NAaHdmr19qQYfTiBace6XUmADvR4Qrhe8gH5uc
RPC URL: https://api.devnet.solana.com
Default Signer: Playground Wallet
Commitment: confirmed

Transaction executed in slot 308150984:
  Block Time: 2024-06-25T12:52:05-05:00
  Version: legacy
  Recent Blockhash: 7AnZvY37nMhCybTyVXJ1umcfHSZGbngnm4GZx6jNRTNH
  Signature 0: 3TewJtiUz1EgtT88pLJHvKFzqrzDNuHVi8CfD2mWmHEBAaMfC5NAaHdmr19qQYfTiBace6XUmADvR4Qrhe8gH5uc
  Signature 1: 3TrRbqeMYFCkjsxdPExxBkLAi9SB2pNUyg87ryBaTHzzYtGjbsAz9udfT9AkrjSo1ZjByJgJHBAdRVVTZv6B87PQ
  Account 0: srw- 3z9vL1zjN6qyAFHhHQdWYRTFAcy69pJydkZmSFBKHg1R (fee payer)
  Account 1: srw- c7yy8zdP8oeZ2ewbSb8WWY2yWjDpg3B43jk3478Nv7J
  Account 2: -r-- 11111111111111111111111111111111
  Account 3: -r-x 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r
  Instruction 0
    Program:   2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r (3)
    Account 0: c7yy8zdP8oeZ2ewbSb8WWY2yWjDpg3B43jk3478Nv7J (1)
    Account 1: 3z9vL1zjN6qyAFHhHQdWYRTFAcy69pJydkZmSFBKHg1R (0)
    Account 2: 11111111111111111111111111111111 (2)
    Data: [175, 175, 109, 31, 13, 152, 155, 237, 42, 0, 0, 0, 0, 0, 0, 0]
  Status: Ok
    Fee: ◎0.00001
    Account 0 balance: ◎5.47001376 -> ◎5.46900152
    Account 1 balance: ◎0 -> ◎0.00100224
    Account 2 balance: ◎0.000000001
    Account 3 balance: ◎0.00139896
  Log Messages:
    Program 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r invoke [1]
    Program log: Instruction: Initialize
    Program 11111111111111111111111111111111 invoke [2]
    Program 11111111111111111111111111111111 success
    Program log: Changed data to: 42!
    Program 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r consumed 5661 of 200000 compute units
    Program 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r success

Confirmed
```

</Accordion>
</Accordions>

Alternatively, you can view the transaction details on
[SolanaFM](https://solana.fm/) or
[Solana Explorer](https://explorer.solana.com/?cluster=devnet) by searching for
the transaction signature (hash).

<Callout>
  Reminder to update the cluster (network) connection on the Explorer you are
  using to match Solana Playground. Solana Playground's default cluster is
  devnet.
</Callout>

### Close Program

Lastly, the SOL allocated to the on-chain program can be fully recovered by
closing the program.

You can close a program by running the following command and specifying the
program address found in `declare_id!()`:

```shell filename="Terminal"
solana program close [ProgramID]
```

For example:

```shell filename="Terminal"
solana program close 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r
```

<Accordions>
<Accordion title="Output">

```shell filename="Terminal"
$ solana program close 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r
Closed Program Id 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r, 2.79511512 SOL reclaimed
```

</Accordion>
</Accordions>

<Accordions>
<Accordion title="Explanation">

Only the upgrade authority of the program can close it. The upgrade authority is
set when the program is deployed, and it's the only account with permission to
modify or close the program. If the upgrade authority is revoked, then the
program becomes immutable and can never be closed or upgraded.

When deploying programs on Solana Playground, your Playground wallet is the
upgrade authority for all your programs.

</Accordion>
</Accordions>

Congratulations! You've just built and deployed your first Solana program using
the Anchor framework!

</Step>
</Steps>
